package socks

import (
	"encoding/binary"
	"runtime"
)

type BufferUtils struct {
	bits []byte
	len  int
	pos  int
}

func (bw *BufferUtils) Write(a any) bool {
	datalen := 0
	switch v := a.(type) {
	case int8:
		bw.bits[bw.pos] = byte(v)
		datalen = 1
	case uint8:
		bw.bits[bw.pos] = byte(v)
		datalen = 1
	case int16:
		binary.LittleEndian.PutUint16(bw.bits[bw.pos:], uint16(v))
		datalen = 2
	case uint16:
		binary.LittleEndian.PutUint16(bw.bits[bw.pos:], uint16(v))
		datalen = 2
	case int:
		binary.LittleEndian.PutUint32(bw.bits[bw.pos:], uint32(v))
		datalen = 4
	case int32:
		binary.LittleEndian.PutUint32(bw.bits[bw.pos:], uint32(v))
		datalen = 4
	case uint32:
		binary.LittleEndian.PutUint32(bw.bits[bw.pos:], uint32(v))
		datalen = 4
	case uint64:
		binary.LittleEndian.PutUint64(bw.bits[bw.pos:], uint64(v))
		datalen = 8
	case int64:
		binary.LittleEndian.PutUint64(bw.bits[bw.pos:], uint64(v))
		datalen = 8
	case []byte:
		datalen = len(v)
		if datalen+int(bw.pos) > int(bw.len) {
			return false
		}
		copyLen := copy(bw.bits[bw.pos:], v)
		return datalen == copyLen
	default:
		return false
	}
	bw.pos += datalen
	return true
}

func (bw *BufferUtils) ReadUint8() (v uint8) {
	v = 0
	if bw.pos < bw.len {
		v = bw.bits[bw.pos]
		bw.pos++
	}
	return v
}

func (bw *BufferUtils) ReadUint16() (v uint16) {
	v = 0
	if bw.pos <= bw.len-2 {
		v = binary.LittleEndian.Uint16(bw.bits[bw.pos:])
		bw.pos += 2
	}
	return v
}

func (bw *BufferUtils) ReadUint32() (v uint32) {
	v = 0
	if bw.pos <= bw.len-4 {
		v = binary.LittleEndian.Uint32(bw.bits[bw.pos:])
		bw.pos += 4
	}
	return v
}

func (bw *BufferUtils) ReadUint64() (v uint64) {
	v = 0
	if bw.pos <= bw.len-8 {
		v = binary.LittleEndian.Uint64(bw.bits[bw.pos:])
		bw.pos += 8
	}
	return v
}

// 支持 Io.reader 接口
func (bw *BufferUtils) Read(buff []byte) (v int, err error) {
	v = bw.len - bw.pos
	len := len(buff)
	if v > len {
		v = len
	}
	if v > 0 {
		copy(buff, bw.bits[bw.pos:])
		bw.pos += v
	}
	return v, nil
}

// 支持 Io.Writer 接口
// func (bw *BufferUtils) Write(buff []byte) (v int, err error) {
// 	v = bw.len - bw.pos
// 	len := len(buff)
// 	if v > len {
// 		v = len
// 	}
// 	if v > 0 {
// 		copy(bw.bits[bw.pos:], buff)
// 		bw.pos += v
// 	}
// 	return v, nil
// }

func (bw *BufferUtils) GetPos() int {
	return bw.pos
}

func (bw *BufferUtils) GetDataLen() int {
	return bw.len
}

// 获取剩余长度
func (bw *BufferUtils) GetRemainLen() int {
	return bw.len - bw.pos
}

// 获取剩余buff
func (bw *BufferUtils) GetRemainBuff() []byte {
	return bw.bits[bw.pos:]
}

// 重新设置指针位置
func (bw *BufferUtils) ResetPos(newPos int) (r bool) {
	r = false
	if (newPos >= 0) && (newPos <= bw.len) {
		bw.pos = newPos
		r = true
	}
	return r
}

// 从当前位置移动指针
func (bw *BufferUtils) Seek(offset int) bool {
	ret := false
	newPos := bw.pos + offset
	if (newPos >= 0) && (newPos < bw.len) {
		ret = true
	}
	return ret
}

func (bw *BufferUtils) Reset(buff []byte) {
	bw.bits = buff
	bw.pos = 0
	bw.len = len(buff)
}

// 自己持有Buff
func (bw *BufferUtils) ResetBuffSize(size int) {
	buff := make([]byte, size)
	bw.Reset(buff)
}

func NewBufferUtils(buff []byte) *BufferUtils {
	var bw BufferUtils
	bw.Reset(buff)
	return &bw
}

func getCallStack() string {
	buff := make([]byte, 1024)
	n := runtime.Stack(buff, true)
	return string(buff[:n])
}
